/****************************************************************************
 * Copyright (c) 2010 Torkild U. Resheim
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Torkild U. Resheim  - initial API and implementation
 *****************************************************************************/
package no.resheim.buildmonitor.core.data;

import java.net.URI;
import java.util.Observable;

/**
 * This type represents a &quot;build&quot;. Each build is associated with a
 * {@link Job}. Whenever one of the data field values is changed, the
 * &quot;changed&quot; state of the instance will be set to true. However no
 * notification will be triggered. It is up to the object that changes the value
 * to also notify observers.
 * 
 * @author Torkild Ulvøy Resheim
 * @since 1.0
 */
public abstract class Build extends Observable {

	/** Whether or not the instance is currently building */
	private boolean building;

	/** The duration of the build */
	private long duration;

	/** The build number */
	private final int number;

	/** The time stamp of the build */
	private final long timestamp;

	/** The URI to the build */
	private final URI uri;

	/**
	 * Returns the duration of the build in milliseconds.
	 * 
	 * @return the duration
	 */
	public final long getDuration() {
		return duration;
	}

	/**
	 * Returns the build number.
	 * 
	 * @return the build number
	 */
	public final int getNumber() {
		return number;
	}

	/**
	 * Returns the time stamp of the build in UNIX time. The time stamp
	 * represents the time the build was started.
	 * 
	 * @return the time stamp
	 */
	public final long getTimestamp() {
		return timestamp;
	}

	/**
	 * Returns a URI to a web page or some other resuource that describes the
	 * particular build.
	 * 
	 * @return the URI
	 */
	public final URI getURI() {
		return uri;
	}

	/**
	 * Returns a boolean indicating whether or not the build is in progress.
	 * 
	 * @return <code>true</code> if the job is building.
	 */
	public final boolean isBuilding() {
		return building;
	}

	/**
	 * Sets the <i>building</i> flag of the build. If this is set to
	 * <code>true</code> the build is in progress. If the value given is
	 * different than the original the changed flag will be set.
	 * 
	 * @param building
	 */
	protected final void setBuilding(boolean building) {
		if (this.building != building) {
			this.building = building;
			setChanged();
		}
	}

	/**
	 * Sets the <i>duration</i> of the build. If the value given is different
	 * than the original the changed flag will be set.
	 * 
	 * @param duration
	 *            the <i>duration</i> in milliseconds.
	 */
	protected final void setDuration(long duration) {
		if (this.duration != duration) {
			this.duration = duration;
			setChanged();
		}
	}

	/**
	 * Creates a new build instance. The URI cannot be <code>null</code> and the
	 * number must be larger than zero.
	 * 
	 * @param uri
	 *            the URI of the build
	 * @param number
	 *            the number of the build
	 * @param timestamp
	 *            the UNIX time when the build was started
	 */
	protected Build(URI uri, int number, long timestamp) {
		if (uri == null) {
			throw new IllegalArgumentException("Build URI cannot be NULL.");
		}
		if (number < 1) {
			throw new IllegalArgumentException(
					"Build number must be larger than zero.");
		}
		this.uri = uri;
		this.number = number;
		this.timestamp = timestamp;
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("Build #");
		sb.append(number);
		return sb.toString();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + number;
		result = prime * result + uri.hashCode();
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Build)) {
			return false;
		}
		Build other = (Build) obj;
		if (number != other.number) {
			return false;
		}
		if (timestamp != other.timestamp) {
			return false;
		}
		if (!uri.equals(other.uri)) {
			return false;
		}
		return true;
	}

}
